﻿#region Using Statements
using System;
using GameBase.Screens;
using GameBase.Sprites;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using StarFox.Sounds;
#endregion

namespace StarFox.ScreenComponents
{
    /// <summary>
    /// Messages associated to GamePlayScreen (game over).
    /// </summary>
    public class GameOverMessage : ScreenComponent2D, IDisposable
    {
        #region Fields

        SpriteSheet spriteSheet;
        GamePlaySound sound;

        // message
        Rectangle dstRectMsg;
        Point initPosMsg;
        Point endPosMsg;

        // background
        Texture2D bkgTex;
        Rectangle bkgRect;

        #endregion

        #region Properties

        /// <summary>
        /// Sets the duration of the message.
        /// </summary>
        public TimeSpan Duration
        {
            private get;
            set;
        }

        #endregion

        #region Screen Transitions

        bool toVisible = false;
        bool toHidden = false;
        float trTime = 0.0f;

        /// <summary>
        /// Makes the component transition to visible state.
        /// </summary>
        public override void Show()
        {
            toVisible = true;
        }

        /// <summary>
        /// Makes the component transition to hidden state.
        /// </summary>
        public override void Hide()
        {
            toHidden = true;
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="screen">The Screen that this ScreenComponent2D is associated to.</param>
        public GameOverMessage(Screen screen)
            : base(screen)
        {
            spriteSheet = Game.Content.Load<SpriteSheet>(ContentSettings.GetAsset("MSG_SPRITES"));

            sound = Game.Services.GetService(typeof(GamePlaySound)) as GamePlaySound;
            if (sound == null)
                throw new InvalidOperationException("Service of type StarFoxSound not found");

            // message
            Rectangle auxRect = spriteSheet.SourceRectangle("MISSION_FAILED");
            dstRectMsg = new Rectangle(0, 0, (int)(auxRect.Width * Screen.Scale), (int)(auxRect.Height * Screen.Scale));
            initPosMsg = new Point(-dstRectMsg.Width, (int)((Screen.Height - dstRectMsg.Height) * 0.5f));
            endPosMsg = new Point((int)((Screen.Width - dstRectMsg.Width) * 0.5f), initPosMsg.Y);
            dstRectMsg.Location = initPosMsg;

            // background
            bkgTex = new Texture2D(Screen.GraphicsDevice, 1, 1);
            bkgTex.SetData(new[] { new Color(51, 51, 51, 191) });
            bkgRect = new Rectangle(0, (int)(Screen.Height * 0.375f), Screen.Width, (int)(Screen.Height * 0.250f));
        }

        #endregion

        #region Dispose

        // dispose flag
        bool isDisposed = false;

        /// <summary>
        /// Immediately releases all resources used by this object.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Allows an object to try to free resources and perform other cleanup operations before it is reclaimed by garbage collection.
        /// </summary>
        ~GameOverMessage()
        {
            Dispose(false);
        }

        /// <summary>
        /// Releases the unmanaged resources used by this object and optionally releases the managed resources.
        /// </summary>
        /// <param name="disposing">true to release both managed and unmanaged resources; false to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (!isDisposed)
            {
                if (disposing)
                {
                    if (bkgTex != null) { bkgTex.Dispose(); bkgTex = null; }
                }

                isDisposed = true;
            }
        }

        #endregion

        #region Game Over

        bool isGameOver_Update;
        bool isGameOver_Draw;
        float gmoTime;

        /// <summary>
        /// Starts a new message.
        /// </summary>
        public void Start()
        {
            isGameOver_Update = true;
            isGameOver_Draw = true;
            Show();
            sound.GameOver();
        }

        /// <summary>
        /// Raised when the message is finishing.
        /// </summary>
        public event EventHandler<EventArgs> Finishing;

        #endregion

        #region Update

        /// <summary>
        /// Called when the ScreenComponent2D needs to be updated.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Update(GameTime gameTime)
        {
            #region Screen Transition

            if (toVisible)
            {
                // update item positions
                float auxTrTime = 1.0f - (float)Math.Pow(1.0f - trTime, 2);
                dstRectMsg.X = initPosMsg.X + (int)(Math.Abs(initPosMsg.X - endPosMsg.X) * auxTrTime);

                // update transition timer
                float trDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / Time.TotalMilliseconds);
                trTime += trDelta;
                trTime = MathHelper.Clamp(trTime, 0.0f, 1.0f);
                if (trTime == 1.0f) { toVisible = false; trTime = 0.0f; }
            }
            else if (toHidden)
            {
                // update item positions
                float auxTrTime = 1.0f - (float)Math.Pow(1.0f - trTime, 2);
                dstRectMsg.X = endPosMsg.X - (int)(Math.Abs(initPosMsg.X - endPosMsg.X) * auxTrTime);

                // update transition timer
                float trDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / Time.TotalMilliseconds);
                trTime += trDelta;
                trTime = MathHelper.Clamp(trTime, 0.0f, 1.0f);
                if (trTime == 1.0f) { toHidden = false; trTime = 0.0f; }
            }

            #endregion

            #region Game Over

            if (isGameOver_Update)
            {
                float timeDelta = (float)(gameTime.ElapsedGameTime.TotalMilliseconds / Duration.TotalMilliseconds);
                gmoTime += timeDelta;
                gmoTime = MathHelper.Clamp(gmoTime, 0.0f, 1.0f);
                if (gmoTime == 1.0f) { isGameOver_Update = false; Finishing(this, EventArgs.Empty); }
            }

            #endregion
        }

        #endregion

        #region Draw

        /// <summary>
        /// Called when the ScreenComponent2D needs to be drawn.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to this method.</param>
        public override void Draw(GameTime gameTime)
        {
            if (isGameOver_Draw)
            {
                // background
                SpriteBatch.Draw(bkgTex, bkgRect, Color.Yellow);

                // message
                SpriteBatch.Draw(spriteSheet.Texture, dstRectMsg, spriteSheet.SourceRectangle("MISSION_FAILED"), Color.Yellow);
            }
        }

        #endregion
    }
}
